﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;
using OpenNETCF.IO.Serial;
using System.Runtime.InteropServices;

namespace poket_m
{
#if true
    [StructLayout(LayoutKind.Explicit)]
    public struct input_ms
    {
        //union
        [FieldOffset(0)]
        public UInt16 seconds;
        [FieldOffset(0)]
        public byte secl;
        [FieldOffset(1)]
        public byte sech;

        [FieldOffset(2)]
        public UInt16 pw1;
        [FieldOffset(4)]
        public UInt16 pw2;
        [FieldOffset(6)]
        public UInt16 rpm;
        [FieldOffset(8)]
        public Int16 adv_deg;
        [FieldOffset(10)]
        public byte squirt;
        [FieldOffset(11)]
        public byte engine;
        [FieldOffset(12)]
        public byte afrtgt1;
        [FieldOffset(13)]
        public byte afrtgt2;
        [FieldOffset(14)]
        public byte wbo2_en1;
        [FieldOffset(15)]
        public byte wbo2_en2;
        [FieldOffset(16)]
        public UInt16 baro;
        [FieldOffset(18)]
        public UInt16 map;
        [FieldOffset(20)]
        public UInt16 mat;
        [FieldOffset(22)]
        public Int16 clt;
        [FieldOffset(24)]
        public UInt16 tps;
        [FieldOffset(26)]
        public UInt16 batt;
        [FieldOffset(28)]
        public UInt16 ego1;
        [FieldOffset(30)]
        public UInt16 ego2;
        [FieldOffset(32)]
        public UInt16 knock;
        [FieldOffset(34)]
        public UInt16 egocor1;
        [FieldOffset(36)]
        public UInt16 egocor2;
        [FieldOffset(38)]
        public UInt16 aircor;
        [FieldOffset(40)]
        public UInt16 warmcor;
        [FieldOffset(42)]
        public UInt16 tpsaccel;
        [FieldOffset(44)]
        public UInt16 tpsfuelcut;
        [FieldOffset(46)]
        public UInt16 barocor;
        [FieldOffset(48)]
        public UInt16 gammae;
        [FieldOffset(50)]
        public UInt16 vecurr1;
        [FieldOffset(52)]
        public UInt16 vecurr2;
        [FieldOffset(54)]
        public UInt16 iacstep;
        [FieldOffset(56)]
        public UInt16 cold_adv_deg;
        [FieldOffset(58)]
        public Int16 tpsdot;
        [FieldOffset(60)]
        public Int16 mapdot;
        [FieldOffset(62)]
        public UInt16 coil_dur;
        [FieldOffset(64)]
        public UInt16 map_acc_en;
        [FieldOffset(66)]
        public UInt16 tps_acc_en;
        [FieldOffset(68)]
        public UInt16 last_acc;
        [FieldOffset(70)]
        public UInt16 spare1;
        [FieldOffset(72)]
        public UInt16 spare2;
        [FieldOffset(74)]
        public UInt16 spare3;
        [FieldOffset(76)]
        public UInt16 spare4;
        [FieldOffset(78)]
        public UInt16 spare5;
        [FieldOffset(80)]
        public UInt16 spare6;
    }
#endif

    public partial class mon : Form
    {
        public static Port port;
        public input_ms m;
        private DetailedPortSettings portSettings;
        private UInt32  rxs_cnt, txs_cnt;
        private bool    file_wr = false;
        private bool file_wr_hd = false;
        private bool flag_light = false;
        private bool flag_light_off = false; 
         
        FileStream fs;
        StreamWriter sw; 

        string TempFile_log_b = "";
        string path;
        public mon()
        {
            InitializeComponent();
            Init();
        }
        
        #region Local Methods
#if false
        public class Backlight
        {
            static public void Enable(bool enable)
            {
                if (enable)
                {
                    DevicePowerNotify("BKL1:", CEDevicePowerState.D0, 1);
                }
                else
                {
                    DevicePowerNotify("BKL1:", CEDevicePowerState.D4, 1);
                }
            }

            private enum CEDevicePowerState
            {
                PwrDeviceUnspecified = -1,
                D0 = 0,
                D1 = 1,
                D2 = 2,
                D3 = 3,
                D4 = 4,
                PwrDeviceMaximum = 5
            }

            [DllImport("coredll.dll", SetLastError = true)]
            extern private static IntPtr DevicePowerNotify(string pvDevice,
                CEDevicePowerState DeviceState, UInt32 StateFlags);
        }
#else
        public class SysPower
        {
            private static IntPtr handle;
            
            static public void Set(CEDevicePowerState state)
            {
                handle = SetPowerRequirement("BKL1:",
                    state, 1, IntPtr.Zero, 0);
            }

            static public void Relese ()
            {
                ReleasePowerRequirement(handle);
            }

            static public void IdleReset ()
            {
                SystemIdleTimerReset();
            }
            
            public enum CEDevicePowerState
            {
                D0 = 0, // Full on
                D1 = 1, // Low on
                D2 = 2, // Standby
                D3 = 3, // Sleep
                D4 = 4, // Off
            }

            [DllImport("coredll.dll", SetLastError = true)]
            extern private static IntPtr SetPowerRequirement(string device,
                CEDevicePowerState ceDevicePowerState, uint deviceFlags,
                IntPtr systemState, ulong stateFlags);
            
            [DllImport("coredll.dll", SetLastError=true)]
            extern private static int ReleasePowerRequirement(IntPtr handle);

            [DllImport("coredll.dll", SetLastError=true)]
            static extern void SystemIdleTimerReset();
        }
#endif
        private void log_term(string str)
        {
            tb_log.Invoke(new EventHandler(delegate
            {
                int cnt = str.Length;
                if ((tb_log.TextLength + cnt) >= tb_log.MaxLength)
                    tb_log.Text = "";
                
                tb_log.Text += (str + Environment.NewLine);
                tb_log.SelectionStart = tb_log.TextLength;
                tb_log.ScrollToCaret();
            }));
        }

        private void log_to_file_b(byte[] d)
        { 
            UInt16 iii = 0;
            StringBuilder sb = new StringBuilder();
            string str = "seconds\tpw1\tpw2\trpm\tadv_deg\tsquirt\tengine\tafrtgt1\tafrtgt2\t" +
                        "wbo2_en1\twbo2_en2\tbaro\tmap\tmat\tclt\ttps\tbatt\tego1\tego2\tknock\t" +
                        "egocor1\tegocor2\taircor\twarmcor\ttpsaccel\ttpsfuelcut\tbarocor\tgammae\t" +
                        "ecurr1\tvecurr2\tiacstep\tcold_adv_deg\ttpsdot\tmapdot\tcoil_dur\t" +
                        "map_acc_en\ttps_acc_en\tlast_acc\tspare1\tspare2\tspare3\tspare4\tspare5\tspare6\t" +
                        "\r\n";
            if (string.IsNullOrEmpty(TempFile_log_b))
            {
                TempFile_log_b = Convert.ToString(DateTime.Now.Ticks);// "tst.txt";//Path.GetRandomFileName();
                TempFile_log_b = path + "raw_" + TempFile_log_b + ".xls";
                fs   = File.Create(TempFile_log_b);
                sw = new StreamWriter(fs);
                sw.Write(str);
            }

            if (!file_wr)
            {
                if (file_wr_hd) {
                    file_wr_hd = false;
                    sw.Write(str);
                }
                return;
            }
            
            iii = 0;
            //Array.Reverse
            //seconds
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //pw1
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //pw2
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //rpm
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //adv_deg
            sb.Append(BitConverter.ToInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //squirt
            sb.Append(d[iii++].ToString());
            sb.Append("\t");

            //engine
            sb.Append(d[iii++].ToString());
            sb.Append("\t");

            //afrtgt1
            sb.Append(d[iii++].ToString());
            sb.Append("\t");

            //afrtgt2
            sb.Append(d[iii++].ToString());
            sb.Append("\t");

            //wbo2_en1
            sb.Append(d[iii++].ToString());
            sb.Append("\t");

            //wbo2_en2
            sb.Append(d[iii++].ToString());
            sb.Append("\t");

            //baro
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //map
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //mat
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //clt
            sb.Append(BitConverter.ToInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //tps
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //batt
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //ego1
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //ego2
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //knock
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //egocor1
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //egocor2
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //aircor
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //warmcor
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //tpsaccel
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //tpsfuelcut
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //barocor
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //gammae
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //vecurr1
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //vecurr2
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //iacstep
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //cold_adv_deg
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //tpsdot
            sb.Append(BitConverter.ToInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //mapdot
            sb.Append(BitConverter.ToInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //coil_dur
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //map_acc_en
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //tps_acc_en
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //last_acc
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //spare1
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //spare2
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //spare3
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //spare4
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //spare5
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");
            iii += 2;

            //spare6
            sb.Append(BitConverter.ToUInt16(d, iii));
            sb.Append("\t");

            sb.Append("\r\n");
            sw.Write(sb.ToString());
        }
#if true
        private static input_ms byte_to_struct(byte[] my_b)
        {
            input_ms mmm = new input_ms();
            GCHandle hDataIn = GCHandle.Alloc(my_b, GCHandleType.Pinned);
            mmm = (input_ms)Marshal.PtrToStructure(hDataIn.AddrOfPinnedObject(),
                                                        typeof(input_ms));
            hDataIn.Free();
            return mmm;
        }
#endif
        private void log_term(byte[] b)
        {
            tb_log.Invoke(new EventHandler(delegate
            {
                int cnt;                
                cnt = b.Length;
                rxs_cnt += Convert.ToUInt32(cnt);
                if (cnt == port.RThreshold)
                {
                    cnt = BitConverter.ToInt16(b, 0);
                    m = byte_to_struct(b);
                    log_term(cnt.ToString());
                    try
                    {
                        log_to_file_b(b);
                    }
                    catch (Exception x) {
                        MessageBox.Show(x.Message, "port",
                                        MessageBoxButtons.OK,
                                        MessageBoxIcon.Exclamation, 
                                        MessageBoxDefaultButton.Button1);
                    }
                }
           }));
        }

        private void Init()
        {
            cmb_potr_sel.Items.Clear();
            foreach (string s in SerialPort.GetPortNames())
                cmb_potr_sel.Items.Add(s);

            // create the port settings
            portSettings = new HandshakeNone();

            // create a default port on COM2 with no handshaking
            port = new Port("COM2:", portSettings);

            // these are fairly inefficient settings
            // for a terminal we want to send/receive all data as it is queued
            // so 1 byte at a time is the best way to go
            port.RThreshold = 82;	// get an event for every 1 byte received
            port.InputLen = 0;		// calling Input will read 1 byte to return not corrupted 2 buffer
            port.SThreshold = 1;	// send 1 byte at a time
            port.Settings.BaudRate = BaudRates.CBR_115200;
            // define an event handler
            port.DataReceived += new Port.CommEvent(port_DataReceived);

            cmb_potr_sel.SelectedIndex = 0;
            ser_open.Text = "&Open";
            btn_send.Enabled = false;
            tb_log.Text += Environment.NewLine + "start...";
            loop_en.BackColor = Color.LightGreen;
            tmr_log.Enabled = false;
            path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase);
            path += "\\";
        }

        #endregion

        private void ser_open_Click(object sender, EventArgs e)
        {
            try
            {
                //if (sp.IsOpen)
                if (port.IsOpen)
                {
                    //sp.Close();
                    port.Close();
                    ser_open.Text = "&Open";
                    tmr_log.Enabled = false;
                    //tmr_backlight.Enabled = false;
                    //Backlight.Enable(true);
                    SysPower.Relese();

                    if (!string.IsNullOrEmpty(TempFile_log_b))
                    {
                        sw.Close();
                        fs.Close();
                        TempFile_log_b = "";
                    }
                }
                else
                {
                    //sp.Open();
                    port.Open();
                    //sp.DiscardInBuffer();
                    //sp.DiscardOutBuffer();
                    ser_open.Text = "&Close";
                }
                //btn_send.Enabled = sp.IsOpen;
                //cmb_potr_sel.Enabled = !sp.IsOpen;
                btn_send.Enabled = port.IsOpen;
                cmb_potr_sel.Enabled = !port.IsOpen;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "port",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
            }
        }    
        private void btn_send_Click(object sender, EventArgs e)
        {
            System.Text.Encoding enc = null;
            enc = new System.Text.ASCIIEncoding();
            int cnt = enc.GetByteCount(txt_send.Text);

            log_term(txt_send.Text);
            
            //if (sp.IsOpen) {
            if (port.IsOpen) {
                byte[] data = new byte[cnt];
                txs_cnt += Convert.ToUInt32(cnt);
                data = enc.GetBytes(txt_send.Text);
                try
                {
                    //sp.Write(data, 0, cnt);
                    //for (int i = 0; i < data.Length; i++)
                    {
                        port.Output = data;
                    }
                }
                
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message, "port",
                        MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                }
            }
        }

        private void tmr_1_Tick(object sender, EventArgs e)
        {
            string TimeInString = "";
            int hour = DateTime.Now.Hour;
            int min = DateTime.Now.Minute;
            int sec = DateTime.Now.Second;

            TimeInString = (hour < 10) ? "0" + hour.ToString() : hour.ToString();
            TimeInString += ":" + ((min < 10) ? "0" + min.ToString() : min.ToString());
            TimeInString += ":" + ((sec < 10) ? "0" + sec.ToString() : sec.ToString());

            SysPower.IdleReset();

            clk.Text = TimeInString;
            clk_bar.Text = TimeInString;

            rx_cnt.Text = "rx: " + rxs_cnt.ToString();
            tx_cnt.Text = "tx: " + txs_cnt.ToString();
            
            lbl_rpm.Text = "Rpm " + m.rpm.ToString();
            if ((bar_rpm.Maximum > m.rpm) &&
                    (m.rpm > bar_rpm.Minimum))
            {
                bar_rpm.Value = m.rpm;
            }
            
            lbl_batt.Text = "Batt " + m.batt.ToString();
            if ((bar_batt.Maximum > m.batt) &&
                    (m.batt > bar_batt.Minimum)) 
            {
                bar_batt.Value = m.batt;
            }

            lbl_map.Text = "Map " + m.map.ToString();
            if ((bar_map.Maximum > m.map) &&
                    (m.map > bar_map.Minimum))
            {
                bar_map.Value = m.map;
            }
            
            lbl_bro.Text = "Baro " + m.baro.ToString();
            if ((bar_baro.Maximum > m.baro) &&
                    (m.baro > bar_baro.Minimum))
            {
                bar_baro.Value = m.baro;
            }

            lbl_ts.Text = "Ts " + m.seconds.ToString();
            if ((bar_ts.Maximum > m.secl) &&
                    (m.secl > bar_ts.Minimum))
            {
                bar_ts.Value = m.secl;
            }

        }

        private void cmb_potr_sel_SelectedIndexChanged(object sender, EventArgs e)
        {
            port.PortName = cmb_potr_sel.Text + ":";
            log_term("selected com ... " + port.PortName);
            //sp.PortName = cmb_potr_sel.Text+":";
            //log_term("selected com ... " + sp.PortName);
        }

        private void loop_en_Click(object sender, EventArgs e)
        {
            tmr_log.Enabled = !tmr_log.Enabled;
            if (tmr_log.Enabled)
                loop_en.BackColor = Color.LightBlue;
            else
                loop_en.BackColor = Color.LightGreen;
        }

        private void tmr_log_Tick(object sender, EventArgs e)
        {
            if (bar_tmr.Value < bar_tmr.Maximum)
                bar_tmr.Value++;
            else
                bar_tmr.Value = bar_tmr.Minimum;
            try
            {
                string s = "a";
                byte[] outputData = new byte[1];
                outputData[0] = Convert.ToByte(s[0]);// s[0];
                port.Output = outputData;
            }
            catch(Exception ex) {
                tmr_log.Enabled = false;
                MessageBox.Show("Error:" + Environment.NewLine +ex.Message,
                    "loop send", MessageBoxButtons.OK, MessageBoxIcon.Asterisk,
                    MessageBoxDefaultButton.Button1);
            }
        }

        private void log_clk_ValueChanged(object sender, EventArgs e)
        {
            tmr_log.Interval = log_clk.Value;
        }

        private void txt_send_GotFocus(object sender, EventArgs e)
        {
            txt_send.SelectAll();
            my_in.Enabled = true;
        }

        private void txt_send_LostFocus(object sender, EventArgs e)
        {
            my_in.Enabled = false;
        }

        private void port_DataReceived()
        {
            // since RThreshold = 1, we get an event for every character
            byte[] inputData = new byte[port.InBufferCount];
            // read the character
            inputData = port.Input;
            log_term(inputData);
        }

        private void log_file_Click(object sender, EventArgs e)
        {
            file_wr = !file_wr;
            if (file_wr)
            {
                log_file.Text = "Log stop";
                log_file.BackColor = Color.LightBlue;
            }
            else
            {
                file_wr_hd = true;
                log_file.Text = "Log start";
                log_file.BackColor = Color.LightGreen;
            }
        }

        private void rt_dusplay_Click(object sender, EventArgs e)
        {
            flag_light = !flag_light;
            lbl_backlight.Text = flag_light.ToString() + " PS";
            if (flag_light)
            {
                SysPower.Set(SysPower.CEDevicePowerState.D0);
            }
            else
            {
                SysPower.Relese();
            }
         }

        private void mon_Closing(object sender, CancelEventArgs e)
        {
            try
            {
                //if (sp.IsOpen)
                if (port.IsOpen)
                {
                    //sp.Close();
                    port.Close();
                    ser_open.Text = "&Open";
                    tmr_log.Enabled = false;
                    //tmr_backlight.Enabled = false;
                    //Backlight.Enable(true);
                    SysPower.Relese();

                    if (!string.IsNullOrEmpty(TempFile_log_b))
                    {
                        sw.Close();
                        fs.Close();
                        TempFile_log_b = "";
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "port",
                    MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
            }
        }
     }
}